import pandas as pd  # 数据处理库，用于读取和操作表格数据
import numpy as np  # 数值计算库，数组与线性代数操作
import matplotlib.pyplot as plt  # 绘图库，用于绘图展示
from sklearn.linear_model import LinearRegression  # 线性回归模型类
from sklearn.model_selection import train_test_split  # 划分训练/测试集的工具（未在部分代码中使用）
from sklearn.metrics import mean_squared_error, r2_score  # 评估指标：MSE 与 R^2
from sklearn.preprocessing import PolynomialFeatures  # 生成多项式特征的工具
import seaborn as sns  # 基于 matplotlib 的统计可视化库
from sklearn.pipeline import Pipeline  # 用于组合预处理与模型的流水线工具
from sklearn.preprocessing import StandardScaler  # 标准化（均值为0、方差为1）
# 加载数据
filepath = "https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBMDeveloperSkillsNetwork-DA0101EN-SkillsNetwork/labs/Data%20files/automobileEDA.csv"  # 数据文件 URL
df = pd.read_csv(filepath)  # 从 URL 读取 CSV 到 DataFrame

lm = LinearRegression()  # 创建线性回归模型实例
X = df[['highway-mpg']]  # 单特征 DataFrame（注意保持二维结构）
Y = df['price']  # 目标变量 Series
lm.fit(X, Y)  # 用单特征拟合线性回归
Yhat = lm.predict(X)  # 在训练集上预测（用于示例、可用于残差分析）
print(Yhat[0:5])  # 打印前 5 个预测值
print(lm.intercept_)  # 打印截距
print(lm.coef_)  # 打印系数（斜率）
Z = df[['horsepower', 'curb-weight', 'engine-size', 'highway-mpg']]  # 多特征 DataFrame
lm.fit(Z, df['price'])  # 用多特征拟合线性回归

print(lm.intercept_)  # 打印多特征模型的截距
print(lm.coef_)  # 打印多特征模型的系数数组
width = 12  # 图像宽（英寸）
height = 10  # 图像高（英寸）
plt.figure(figsize=(width, height))  # 新建图形并设置大小
sns.regplot(x="highway-mpg", y="price", data=df)  # 绘制回归拟合图（散点+拟合线）
plt.ylim(0,)  # 纵轴下限设为 0
plt.show()  # 显示图形
plt.figure(figsize=(width, height))  # 新图
sns.regplot(x="peak-rpm", y="price", data=df)  # 绘制 peak-rpm 与 price 的回归图
plt.ylim(0,)
plt.show()
width = 12  # 重复设置（可合并），再次定义画布大小
height = 10
plt.figure(figsize=(width, height))
sns.residplot(x=df['highway-mpg'], y=df['price'])  # 绘制残差图（用于检查模型假设）
plt.show()
Y_hat = lm.predict(Z)  # 用多特征模型预测（用于分布比较）
plt.figure(figsize=(12, 10))
ax1 = sns.kdeplot(df['price'], color="r", label="Actual Value")  # 绘制真实 price 的 KDE
sns.kdeplot(Y_hat, color="b", label="Fitted Values", ax=ax1)  # 在同一图上叠加预测值的 KDE
ax1.set_title('Actual vs Fitted Values for Price (KDE)')
ax1.set_xlabel('Price (in dollars)')
ax1.set_ylabel('Density')
ax1.legend()  # 显示图例
plt.show()
def PlotPolly(model, independent_variable, dependent_variabble, Name):
    """用 matplotlib 绘制多项式拟合曲线与原始点的辅助函数"""
    x_new = np.linspace(15, 55, 100)  # 在 x 的范围内生成平滑网格用于绘制曲线
    y_new = model(x_new)  # 用传入的可调用模型计算网格上的预测值

    plt.plot(independent_variable, dependent_variabble, '.', x_new, y_new, '-')  # 绘制散点与拟合曲线
    plt.title('Polynomial Fit with Matplotlib for Price ~ Length')  # 图标题
    ax = plt.gca()  # 获取当前坐标轴对象
    ax.set_facecolor((0.898, 0.898, 0.898))  # 设置坐标系背景色
    fig = plt.gcf()  # 获取当前 figure（如需保存可用）
    plt.xlabel(Name)  # x 轴标签
    plt.ylabel('Price of Cars')  # y 轴标签

    plt.show()  # 显示图形
    plt.close()  # 关闭图形释放内存
x = df['highway-mpg']  # 抽取单特征作为多项式拟合的自变量
y = df['price']  # 目标变量
f = np.polyfit(x, y, 3)  # 用最小二乘拟合 3 次多项式，返回系数
p = np.poly1d(f)  # 将系数封装为可调用的多项式对象
print(p)  # 打印多项式表达式
PlotPolly(p, x, y, 'highway-mpg')  # 用上面定义的函数绘制多项式拟合图
pr = PolynomialFeatures(degree=2)  # 生成二次多项式特征的转换器
Z_pr = pr.fit_transform(Z)  # 将 Z 扩展为多项式特征矩阵
print(Z.shape)  # 打印原始特征矩阵形状 (n_samples, n_features)
print(Z_pr.shape)  # 打印扩展后特征矩阵形状
Input = [('scale', StandardScaler()), ('polynomial', PolynomialFeatures(include_bias=False)), ('model', LinearRegression())]  # 定义 Pipeline 步骤
pipe = Pipeline(Input)  # 创建 Pipeline（scale -> polynomial -> model）
print(pipe)  # 打印 pipeline 描述
Z = Z.astype(float)  # 确保特征为浮点型以便后续计算
pipe.fit(Z, y)  # 在原始特征上训练 pipeline（注意 pipeline 内部会按步骤运行）
yhat = pipe.predict(Z)  # 使用 pipeline 做预测（输入为原始特征矩阵）
print(yhat[0:4])  # 打印前 4 个预测值
# highway_mpg_fit
lm.fit(X, Y)  # 使用单特征再次拟合线性回归（覆盖之前的 lm 状态）
# Find the R^2
print('The R-square is: ', lm.score(X, Y))  # 打印单特征模型的 R^2
mse = mean_squared_error(df['price'], Yhat)  # 计算原始单特征模型的 MSE（使用之前的 Yhat）
print('The mean square error of price and predicted value is: ', mse)
# fit the model 
lm.fit(Z, df['price'])  # 用多特征再次拟合线性回归（覆盖 lm）
# Find the R^2
print('The R-square is: ', lm.score(Z, df['price']))  # 打印多特征模型的 R^2
Y_predict_multifit = lm.predict(Z)  # 多特征模型的预测值
mse = mean_squared_error(df['price'], Y_predict_multifit)  # 多特征模型的 MSE
print('The mean square error of price and predicted value using multifit is: ', mse)
r_squared = r2_score(y, p(x))  # 多项式拟合（p）的 R^2（与线性模型不同）
print('The R-square value is: ', r_squared)
mse = mean_squared_error(y, p(x))  # 多项式拟合的 MSE
print('The mean square error of price and predicted value using polynomial fit is: ', mse)
new_input = np.arange(1, 100, 1).reshape(-1, 1)  # 生成 1..99 的列向量，供 predict 使用
lm.fit(X, Y)  # 重新拟合单特征线性回归（以便对 new_input 预测）
yhat = lm.predict(new_input)  # 预测 new_input 对应的 price
print(yhat[0:4])
plt.plot(new_input, yhat)
plt.show()
